package site.abcky.vbox;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;

import org.gnome.gtk.Gtk;
import org.gnome.notify.Notification;
import org.gnome.notify.Notify;
import org.mozilla.xpcom.XPCOMException;
import org.virtualbox_6_1.BitmapFormat;
import org.virtualbox_6_1.GuestMonitorStatus;
import org.virtualbox_6_1.Holder;
import org.virtualbox_6_1.IDisplay;
import org.virtualbox_6_1.IMachine;
import org.virtualbox_6_1.IProgress;
import org.virtualbox_6_1.ISession;
import org.virtualbox_6_1.IVirtualBox;
import org.virtualbox_6_1.LockType;
import org.virtualbox_6_1.VBoxException;
import org.virtualbox_6_1.VirtualBoxManager;

/**
 * Hello world!
 *
 */
public class App {
	public static void main(String[] args) throws IOException {
		Gtk.init(args);
		Notify.init("Virtualbox Message");

		VirtualBoxManager manager = VirtualBoxManager.createInstance(null);
		IVirtualBox vbox = manager.getVBox();
		ISession session = manager.getSessionObject();

		List<IMachine> list = vbox.getMachines();
		for (int i = 0; i < list.size(); i++) {
			String name = list.get(i).getName();
			System.out.println((i + 1) + ": " + name);
		}

		Scanner scanner = new Scanner(System.in);
		int i = readSeq(scanner, list.size());
		scanner.close();
		IMachine machine = list.get(i - 1);
		lockMachine(machine, session);
	}

	private static int readSeq(Scanner scanner, int length) {
		System.out.printf("请输入虚拟机序号，(1-%d), 输入q退出:\n", length);
		String str = scanner.next();
		if (str.equals("q")) {
			System.exit(0);
		} else {
			try {
				int i = Integer.parseInt(str);
				if (i >= 1 && i <= length) {
					return i;
				} else {
					System.out.print("输入失败，");
					return readSeq(scanner, length);
				}
			} catch (Exception e) {
				System.out.print("输入失败，");
				return readSeq(scanner, length);
			}
		}
		return 0;

	}

	private static void lockMachine(IMachine machine, ISession session) throws IOException {
		try {
			System.out.println("启动虚拟机...");
			IProgress progess = machine.launchVMProcess(session, "", Arrays.asList());
			progess.waitForCompletion(-1);
		} catch (VBoxException e) {
			System.out.println("启动失败:" + e.getMessage());
			System.out.println("尝试连接...");
			machine.lockMachine(session, LockType.Shared);
			System.out.println("连接成功，开始判断消息...");
		}

		IDisplay display = session.getConsole().getDisplay();
		Holder<Long> width = new Holder<>(0l);
		Holder<Long> height = new Holder<>(0l);
		Holder<Long> bpp = new Holder<>(0l);
		Holder<Integer> x = new Holder<>(0);
		Holder<Integer> y = new Holder<>(0);
		Holder<GuestMonitorStatus> guestMonitorStatus = new Holder<GuestMonitorStatus>(GuestMonitorStatus.fromValue(0));

		byte[] last = null;
		while (true) {
			display.getScreenResolution(0l, width, height, bpp, x, y, guestMonitorStatus);

			byte[] bs = capture(display, width.value, height.value);
			System.out.printf("length %d, width %d, height %d\n", bs.length, width.value, height.value);

			bs = newRect(bs, width.value, height.value, 0, width.value, height.value - 40, height.value);
			if (!bytesEqual(last, bs)) {
				System.out.println("new message");
				sendMessage();
			} else {
				System.out.println("no message");
			}
			last = bs;

			// capturePng(display, width.value, height.value);
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private static byte[] capture(IDisplay display, long width, long height) {
		byte[] bs = display.takeScreenShotToArray(0l, width, height, BitmapFormat.RGBA);
		return bs;
	}

	private static byte[] capturePng(IDisplay display, long width, long height) {
		byte[] bs = display.takeScreenShotToArray(0l, width, height, BitmapFormat.PNG);
		try {
			writeFile(bs);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return bs;
	}

	private static void writeFile(byte[] bs) throws IOException {
		String filepath = "/home/yuanman/wechat/" + System.currentTimeMillis();
		File file = new File(filepath);
		if (file.exists()) {
			file.delete();
		}
		FileOutputStream fos = new FileOutputStream(file);
		fos.write(bs, 0, bs.length);
		fos.flush();
		fos.close();

	}

	private static byte[] newRect(byte[] bs, long width, long height, long left, long right, long top, long bottom) {
		byte[] b = new byte[(int) ((right - left) * (bottom - top) * 4)];
		int j = 0;
		for (int i = 0; i < bs.length; i++) {
			if (i / 4 % width >= left && i / 4 % width < right && i / 4 / width >= top && i / 4 / width < bottom) {
				b[j++] = bs[i];
			}
		}

		return b;
	}

	private static boolean bytesEqual(byte[] a, byte[] b) {
		if (a == null || b == null) {
			return true;
		}
		if (a.length != b.length) {
			return true;
		}
		for (int i = 0; i < a.length; i++) {
			if (a[i] != b[i]) {
				return false;
			}
		}
		return true;
	}

	private static void sendMessage() {
		Notification Hello = new Notification("Virtualbox Message", "您有新消息了", "virtualbox");
		Hello.show();
	}
}
